﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace TinyPG
{
    class Dessinateur
    {
        private Graphics _gr;
        private Pen pen = new Pen(Brushes.Black);

        private StringFormat formatEtape = new StringFormat(StringFormatFlags.NoClip);
        private StringFormat formatRecep = new StringFormat(StringFormatFlags.NoClip);

        public Dessinateur()
        {
            formatEtape.LineAlignment = StringAlignment.Center;
            formatEtape.Alignment = StringAlignment.Center;
            formatRecep.LineAlignment = StringAlignment.Center;
            formatRecep.Alignment = StringAlignment.Near;

        }

        private int _zoom = 50;

        public void SetGraphics(Graphics gr)
        {
            _gr = gr;
        }


        public void ReSetZoom()
        {
            _zoom = 50;
        }

        public void SetZoom(int PlusMoin)
        {
            if (PlusMoin < 0)
            {
                if (_zoom > 10)
                {
                    _zoom = _zoom - 10;
                }
            }
            else
            {
                if (_zoom < 110)
                {
                    _zoom = _zoom + 10;
                }
            }
        }

        public int GetZoom()
        {
            return _zoom;
        }

        public void DessineEtape(Etape E, float x, float y)
        {
            
            Point p1 = new Point((int)((x + 0.5) * (_zoom)), (int)((y + 0.9) * (_zoom)));
            Point p2 = new Point((int)((x + 0.5) * (_zoom)), (int)((y + 1) * (_zoom)));
            Point p3 = new Point((int)((x + 0.5) * (_zoom)), (int)((y * (_zoom))));
            Point p4 = new Point((int)((x + 0.5) * (_zoom)), (int)((y + 0.1) * (_zoom)));
            _gr.DrawLine(pen, p1, p2);
            _gr.DrawLine(pen, p3, p4);
            
            Point p5 = new Point((int)((x + 0.1 ) * (_zoom)), (int)((y + 0.1) * (_zoom)));
            Point p6 = new Point((int)((x + 0.1 ) * (_zoom)), (int)((y + 0.9) * (_zoom)));
            Point p7 = new Point((int)((x + 0.9 ) * (_zoom)), (int)((y + 0.1) * (_zoom)));
            Point p8 = new Point((int)((x + 0.9 ) * (_zoom)), (int)((y + 0.9) * (_zoom)));
            Point[] CarreEtape = new Point[] { p5, p6, p8, p7, p5 };
            _gr.DrawLines(pen, CarreEtape);

            if (E.GetInit())
            {
                Point p9 = new Point((int)((x + 0.2 ) * (_zoom)), (int)((y + 0.2) * (_zoom)));
                Point p10 = new Point((int)((x + 0.2 ) * (_zoom)), (int)((y + 0.8) * (_zoom)));
                Point p11 = new Point((int)((x + 0.8 ) * (_zoom )), (int)((y + 0.2) * (_zoom)));
                Point p12 = new Point((int)((x + 0.8 ) * (_zoom )), (int)((y + 0.8) * (_zoom)));
                Point[] CarreInit = new Point[] { p9, p10, p12, p11, p9 };
            
                _gr.DrawLines(pen, CarreInit);
            }
            
            Rectangle ZoneAff = new Rectangle(p5, new Size((int)(_zoom * 0.8), (int)(_zoom * 0.8)));
            _gr.DrawString(E.GetId(), new Font("Arial", (int)(_zoom * 0.2), FontStyle.Regular), Brushes.Black, (RectangleF)ZoneAff, formatEtape);
            
            int i = 1;
            foreach (string S in E._listActions)
            {
                Point p13 = new Point((int)((x + 0.1 + i) * (_zoom)), (int)((y + 0.1) * (_zoom)));
                Point p14 = new Point((int)((x + 0.1 + i) * (_zoom)), (int)((y + 0.9) * (_zoom)));
                Point p15 = new Point((int)((x + 0.9 + i) * (_zoom)), (int)((y + 0.1) * (_zoom)));
                Point p16 = new Point((int)((x + 0.9 + i) * (_zoom)), (int)((y + 0.9) * (_zoom)));
                Point p17 = new Point((int)((x - 0.1 + i) * (_zoom)), (int)((y + 0.5) * (_zoom)));
                Point p18 = new Point((int)((x + 0.1 + i) * (_zoom)), (int)((y + 0.5) * (_zoom)));
                Point[] CarreAction = new Point[] { p17, p18, p13, p15, p16, p14, p18 };

                _gr.DrawLines(pen, CarreAction);

                Rectangle ZoneAffAct = new Rectangle(p13, new Size((int)(_zoom * 0.8), (int)(_zoom * 0.8)));
                _gr.DrawString(S, new Font("Arial", (int)(_zoom * 0.2), FontStyle.Regular), Brushes.Black, (RectangleF)ZoneAffAct, formatEtape);
                i++;
            }
        }

        public void DessineReceptivite(Receptivite R, float x, float y)
        {


            Point p1 = new Point((int)((x + 0.5) * (_zoom)), (int)((y + 0) * (_zoom)));
            Point p2 = new Point((int)((x + 0.5) * (_zoom)), (int)((y + 1) * (_zoom)));
            _gr.DrawLine(pen, p1, p2);

            Point p3 = new Point((int)((x + 0.3) * (_zoom)), (int)((y + 0.5) * (_zoom)));
            Point p4 = new Point((int)((x + 0.7) * (_zoom)), (int)((y + 0.5) * (_zoom)));
            _gr.DrawLine(pen, p3, p4);

            Point p5 = new Point((int)((x + 0.7) * (_zoom)), (int)(y * (_zoom)));
            Rectangle ZoneAff = new Rectangle(p5, new Size((int)(_zoom), (int)(_zoom)));
            _gr.DrawString(R.GetName(), new Font("Arial", (int)(_zoom * 0.2), FontStyle.Regular), Brushes.Black, (RectangleF)ZoneAff, formatRecep);



        }

        public void DessineBranche(Branche B, ref int i)
        {
            if (!B._beginEnd && !B._isNoeud)
            {
                if (B._listElements.Count > 0)
                {
                    if (!B._listElements[0].GetInit())
                    {
                        DessineNoeudAmont(B._listBranchePrev, B);
                    }
                }
                else
                {
                    DessineNoeudAmont(B._listBranchePrev, B);
                }

            }

            int k = 0;
            foreach (Element E in B._listElements)
            {

                if (E.GetType() == typeof(Etape))
                {
                    Etape EtapeAdessiner = (Etape)E;
                    DessineEtape(EtapeAdessiner, B._Xpos, B._Ypos + k);
                }
                else
                {
                    Receptivite RecepADessiner = (Receptivite)E;
                    DessineReceptivite(RecepADessiner, B._Xpos, B._Ypos + k);
                }
                k++;
            }

            if (!B._beginEnd && !B._isNoeud)
            {
                if (!B._listBrancheNext[0]._beginEnd)
                {
                    DessineNoeudAval(B._listBrancheNext, B);
                }


            }

            foreach (Branche Br in B._listBrancheRetourAval)
            {
                if (Br._listElements.Count > 0)
                {
                    if (Br._listElements[0].GetInit())
                    {
                        DessineRetour(B, Br, i);
                        i++;
                    }
                    else
                    {
                        DessineViensDe(Br);
                        //DessineVaA(B);
                    }
                }
                else
                {
                    DessineViensDe(Br);
                    DessineVaA(B);
                }
                
            }



        }

        public List<Element> RechercheNextElmt(Branche B)
        {
            List<Element> ListRetour = new List<Element>();
            if (B._listElements.Count > 0)
            {
                ListRetour.Add(B._listElements[0]);
            }
            else
            {
                foreach (Branche Br in B._listBrancheNext)
                {
                    foreach (Element E in RechercheNextElmt(Br))
                    {
                        ListRetour.Add(E);
                    }
                }
            }
            return ListRetour;
        }

        public void DessineVaA(Branche B)
        {

            Point p1 = new Point((int)((B._Xpos + 0.5) * (_zoom)), (int)((B._Ypos) * (_zoom)));
            Point p2 = new Point((int)((B._Xpos + 0.2) * (_zoom)), (int)((B._Ypos - 0.3) * (_zoom)));

            Point p3 = new Point((int)((B._Xpos + 0.8) * (_zoom)), (int)((B._Ypos -0.3) * (_zoom)));

            _gr.DrawLine(pen, p1, p2);
            _gr.DrawLine(pen, p1, p3);

            List<Element> _listE = RechercheNextElmt(B._listBrancheRetourAval[0]);
            int i = 0;
            foreach (Element E in _listE)
            {
                Point p4 = new Point((int)((B._Xpos + 0.2 + i * 0.2) * (_zoom)), (int)((B._Ypos - 0.2) * (_zoom)));
                Rectangle ZoneAff = new Rectangle(p4, new Size((int)(_zoom), (int)(_zoom)));
                if (E.GetType() == typeof(Etape))
                {
                    Etape Et = (Etape)E;
                    _gr.DrawString("e" + Et.GetId(), new Font("Arial", (int)(_zoom * 0.2), FontStyle.Regular), Brushes.Black, (RectangleF)ZoneAff, formatRecep);
                }
                else
                {
                    Receptivite R = (Receptivite)E;
                    _gr.DrawString(R.GetName(), new Font("Arial", (int)(_zoom * 0.2), FontStyle.Regular), Brushes.Black, (RectangleF)ZoneAff, formatRecep);
                }
                i++;
            }
        }



        public List<Element> RechercheLastElmt(Branche B)
        {
            List<Element> ListRetour = new List<Element>();
            if (B._listElements.Count > 0)
            {
                ListRetour.Add(B._listElements[B._listElements.Count - 1]);
            }
            else
            {
                foreach (Branche br in B._listBranchePrev)
                {
                    foreach (Element E in RechercheLastElmt(br))
                    {
                        ListRetour.Add(E);
                    }
                }
            }
            return ListRetour;

        }

        public void DessineViensDe(Branche B)
        {
            Point p1 = new Point((int)((B._Xpos + 0.5) * (_zoom)), (int)((B._Ypos - 0.5 ) * (_zoom)));
            Point p2 = new Point((int)((B._Xpos + 0.5) * (_zoom)), (int)((B._Ypos - 1) * (_zoom)));
            _gr.DrawLine(pen, p1, p2);
            Point p3 = new Point((int)((B._Xpos + 0.2) * (_zoom)), (int)((B._Ypos - 1.3) * (_zoom)));
            Point p4 = new Point((int)((B._Xpos + 0.8) * (_zoom)), (int)((B._Ypos - 1.3) * (_zoom)));
            _gr.DrawLine(pen, p2, p3);
            _gr.DrawLine(pen, p2, p4);


            List<Element> _listE = RechercheLastElmt(B._listBrancheRetourAmont[0]);
            int i=0;
            foreach(Element E in _listE)
            {
                Point p5 = new Point((int)((B._Xpos + 0.2 + i*0.2) * (_zoom)), (int)((B._Ypos - 2) * (_zoom)));
                Rectangle ZoneAff = new Rectangle(p5, new Size((int)(_zoom), (int)(_zoom)));
                if (E.GetType() == typeof(Etape))
                {
                    Etape Et = (Etape)E;
                    _gr.DrawString("e" + Et.GetId(), new Font("Arial", (int)(_zoom * 0.2), FontStyle.Regular), Brushes.Black, (RectangleF)ZoneAff, formatRecep);
                }
                else
                {
                    Receptivite R = (Receptivite)E;
                    _gr.DrawString(R.GetName(), new Font("Arial", (int)(_zoom * 0.2), FontStyle.Regular), Brushes.Black, (RectangleF)ZoneAff, formatRecep);
                }
                i++;
            }

        }

        public void DessineNoeudAmont(List<Branche> BAmont, Branche BAval)
        {
            if (BAmont.Count == 1)
            {

                Point p1 = new Point((int)((BAval._Xpos + 0.5) * (_zoom)), (int)((BAval._Ypos - 0.5) * (_zoom)));
                Point p2 = new Point((int)((BAval._Xpos + 0.5) * (_zoom)), (int)((BAval._Ypos + 0) * (_zoom)));
                _gr.DrawLine(pen, p1, p2);
            }
            else
            {
                Point p3 = new Point((int)((BAval._Xpos + 0.5) * (_zoom)), (int)((BAval._Ypos - 0.25) * (_zoom)));
                Point p4 = new Point((int)((BAval._Xpos + 0.5) * (_zoom)), (int)((BAval._Ypos + 0) * (_zoom)));
                _gr.DrawLine(pen, p3, p4);

                float Xmin = BAval._Xpos;
                float Xmax = BAval._Xpos;
                foreach (Branche B in BAmont)
                {

                    if (Xmin > B._Xpos)
                    {
                        Xmin = B._Xpos;
                    }

                    if (Xmax < B._Xpos)
                    {
                        Xmax = B._Xpos;
                    }
                    Point p5 = new Point((int)((B._Xpos + 0.5) * (_zoom)), (int)((B._Ypos - 0.5) * (_zoom)));
                    Point p6 = new Point((int)((B._Xpos + 0.5) * (_zoom)), (int)((BAval._Ypos - 0.30) * (_zoom)));
                    _gr.DrawLine(pen, p5, p6);
                }
                Point p7 = new Point((int)((Xmin + 0.3) * (_zoom )), (int)((BAval._Ypos - 0.30) * (_zoom)));
                Point p8 = new Point((int)((Xmax + 0.7) * (_zoom)), (int)((BAval._Ypos - 0.30) * (_zoom)));
                _gr.DrawLine(pen, p7, p8);

                if (BAval._listElements.Count > 0)
                {
                    if (BAval._listElements[0].GetType() == typeof(Etape))
                    {
                        Point p9 = new Point((int)((BAval._Xpos + 0.5) * (_zoom)), (int)((BAval._Ypos - 0.25) * (_zoom)));
                        Point p10 = new Point((int)((BAval._Xpos + 0.5) * (_zoom)), (int)((BAval._Ypos - 0.30) * (_zoom)));
                        _gr.DrawLine(pen, p9, p10);

                    }
                    else
                    {
                        Point p11 = new Point((int)((Xmin + 0.3) * (_zoom)), (int)((BAval._Ypos - 0.25) * (_zoom)));
                        Point p12 = new Point((int)((Xmax + 0.7) * (_zoom)), (int)((BAval._Ypos - 0.25) * (_zoom)));
                        _gr.DrawLine(pen, p11, p12);
                    }
                }
                else
                {
                    if (BAmont[0]._listBranchePrev[0]._listElements[BAmont[0]._listBranchePrev[0]._listElements.Count - 1].GetType() == typeof(Receptivite))
                    {
                        Point p9 = new Point((int)((BAval._Xpos + 0.5) * (_zoom )), (int)((BAval._Ypos - 0.25) * (_zoom)));
                        Point p10 = new Point((int)((BAval._Xpos + 0.5) * (_zoom )), (int)((BAval._Ypos - 0.30) * (_zoom)));
                        _gr.DrawLine(pen, p9, p10);

                    }
                    else
                    {
                        Point p11 = new Point((int)((Xmin + 0.3) * (_zoom )), (int)((BAval._Ypos - 0.25) * (_zoom)));
                        Point p12 = new Point((int)((Xmax + 0.7) * (_zoom)), (int)((BAval._Ypos - 0.25) * (_zoom)));
                        _gr.DrawLine(pen, p11, p12);
                    }
                }
            }
        }

        public void DessineNoeudAval(List<Branche> BAval, Branche BAmont)
        {

            if (BAval.Count == 1)
            {


                Point p1 = new Point((int)((BAmont._Xpos + 0.5) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count) * (_zoom)));
                Point p2 = new Point((int)((BAmont._Xpos + 0.5) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count + 0.5) * (_zoom)));
                _gr.DrawLine(pen, p1, p2);
            }
            else
            {
                Point p3 = new Point((int)((BAmont._Xpos + 0.5) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count) * (_zoom)));
                Point p4 = new Point((int)((BAmont._Xpos + 0.5) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count + 0.25) * (_zoom)));
                _gr.DrawLine(pen, p3, p4);

                float Xmin = BAmont._Xpos;
                float Xmax = BAmont._Xpos;
                foreach (Branche B in BAval)
                {

                    if (Xmin > B._Xpos)
                    {
                        Xmin = B._Xpos;
                    }

                    if (Xmax < B._Xpos)
                    {
                        Xmax = B._Xpos;
                    }
                    if (!B._beginEnd)
                    {
                        Point p5 = new Point((int)((B._Xpos + 0.5) * (_zoom )), (int)((B._Ypos - 0.5) * (_zoom)));
                        Point p6 = new Point((int)((B._Xpos + 0.5) * (_zoom)), (int)((BAmont._Ypos + BAmont._listElements.Count + 0.30) * (_zoom)));
                        _gr.DrawLine(pen, p5, p6);
                    }
                }
                Point p7 = new Point((int)((Xmin + 0.3) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count + 0.30) * (_zoom)));
                Point p8 = new Point((int)((Xmax + 0.7) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count + 0.30) * (_zoom)));
                _gr.DrawLine(pen, p7, p8);

                if (BAmont._listElements.Count > 0)
                {
                    if (BAmont._listElements[BAmont._listElements.Count - 1].GetType() == typeof(Etape))
                    {
                        Point p9 = new Point((int)((BAmont._Xpos + 0.5) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count + 0.25) * (_zoom)));
                        Point p10 = new Point((int)((BAmont._Xpos + 0.5) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count + 0.30) * (_zoom)));
                        _gr.DrawLine(pen, p9, p10);

                    }
                    else
                    {
                        Point p11 = new Point((int)((Xmin + 0.3) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count + 0.25) * (_zoom)));
                        Point p12 = new Point((int)((Xmax + 0.7) * (_zoom )), (int)((BAmont._Ypos + BAmont._listElements.Count + 0.25) * (_zoom)));
                        _gr.DrawLine(pen, p11, p12);
                    }
                }
            }
        }

        public void DessineRetour(Branche BDepart, Branche BArrivee, int i)
        {
            Point p1 = new Point((int)((BDepart._Xpos + 0.5) * (_zoom )), (int)((BDepart._Ypos) * (_zoom)));
            Point p2 = new Point((int)((BDepart._Xpos + 0.5) * (_zoom )), (int)((Document.Doc._listeLesBranches[Document.Doc._listeLesBranches.Count - 1]._Ypos - 1 + ((i + 1) * 0.2)) * (_zoom)));
            Point p3 = new Point((int)((Document.Doc._listeLesBranches[Document.Doc._listeLesBranches.Count - 2]._Xmin - ((i + 1) * 0.2)) * (_zoom )), (int)((Document.Doc._listeLesBranches[Document.Doc._listeLesBranches.Count - 1]._Ymin - 1 + ((i + 1) * 0.2)) * (_zoom)));
            Point p4 = new Point((int)((Document.Doc._listeLesBranches[Document.Doc._listeLesBranches.Count - 2]._Xmin - ((i + 1) * 0.2)) * (_zoom)), (int)((Document.Doc._listeLesBranches[Document.Doc._listeLesBranches.Count - 2]._Ymin +1- ((i + 1) * 0.2)) * (_zoom)));
            Point p5 = new Point((int)((BArrivee._Xpos + 0.5) * (_zoom)), (int)((Document.Doc._listeLesBranches[Document.Doc._listeLesBranches.Count - 2]._Ypos +1- ((i + 1) * 0.2)) * (_zoom)));
            Point p6 = new Point((int)((BArrivee._Xpos + 0.5) * (_zoom )), (int)((BArrivee._Ypos) * (_zoom)));
            Point[] Retour = new Point[] { p1, p2, p3, p4, p5, p6 };
            _gr.DrawLines(pen, Retour);
        }
    }
}
